package cn.itcast.tanhua.mytanhuaserver.interceptor;

import cn.hutool.core.util.StrUtil;
import cn.itcast.tanhua.KWSeekerManage;
import cn.itcast.tanhua.SensitiveWordResult;
import cn.itcast.tanhua.SimpleKWSeekerProcessor;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.IAcsClient;
import com.aliyuncs.exceptions.ClientException;
import com.aliyuncs.exceptions.ServerException;
import com.aliyuncs.green.model.v20180509.ImageSyncScanRequest;
import com.aliyuncs.green.model.v20180509.TextScanRequest;
import com.aliyuncs.http.FormatType;
import com.aliyuncs.http.HttpResponse;
import com.aliyuncs.http.MethodType;
import com.aliyuncs.http.ProtocolType;
import com.aliyuncs.profile.DefaultProfile;
import com.aliyuncs.profile.IClientProfile;
import net.sourceforge.tess4j.ITesseract;
import net.sourceforge.tess4j.Tesseract;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import java.io.*;
import java.util.*;

/**
 * @author 胡桂明
 * @since 2021/12/6 15:24
 */
@Component
public class AliYunFilter {
    @Value("${aliyun.regionId}")
    private String regionId;
    @Value("${aliyun.accessKeyId}")
    private String accessKeyId;
    @Value("${aliyun.accessKeySecret}")
    private String accessKeySecret;

    /**
     * 文字审核
     *
     * @param textContent
     * @return
     * @throws Exception
     */
    public String testing(String textContent) throws Exception {

        //请替换成你自己的accessKeyId、accessKeySecret
        IClientProfile profile = DefaultProfile.getProfile(regionId, accessKeyId, accessKeySecret);
        IAcsClient client = new DefaultAcsClient(profile);

        TextScanRequest textScanRequest = new TextScanRequest();
        // 指定api返回格式
        textScanRequest.setSysAcceptFormat(FormatType.JSON);
        textScanRequest.setHttpContentType(FormatType.JSON);
        // 指定请求方法
        textScanRequest.setSysMethod(com.aliyuncs.http.MethodType.POST);
        textScanRequest.setSysEncoding("UTF-8");
        textScanRequest.setSysRegionId("cn-shanghai");

        List<Map<String, Object>> tasks = new ArrayList<>();
        Map<String, Object> task1 = new LinkedHashMap<>();
        task1.put("dataId", UUID.randomUUID().toString());
        /**
         * 待检测的文本，长度不超过10000个字符
         */
        task1.put("content", textContent);
        tasks.add(task1);

        JSONObject data = new JSONObject();

        /**
         * 检测场景，文本垃圾检测传递：antispam
         **/
        data.put("scenes", Arrays.asList("antispam"));
        data.put("tasks", tasks);
//        System.out.println(JSON.toJSONString(data, true));
        textScanRequest.setHttpContent(data.toJSONString().getBytes("UTF-8"), "UTF-8", FormatType.JSON);
        // 请务必设置超时时间
        textScanRequest.setSysConnectTimeout(3000);
        textScanRequest.setSysReadTimeout(6000);
        try {
            HttpResponse httpResponse = client.doAction(textScanRequest);

            // 检测响应
            if (!httpResponse.isSuccess()) {
                System.out.println("响应不成功。地位:" + httpResponse.getStatus());
                return null;
            }
            JSONObject scrResponse = JSON.parseObject(new String(httpResponse.getHttpContent(), "UTF-8"));

            // 判断状态码
            if (200 != scrResponse.getInteger("code")) {
                System.out.println("检测不成功。代码:" + scrResponse.getInteger("code"));
                return null;
            }
            JSONArray taskResults = scrResponse.getJSONArray("data");

            int flag = 0;
            // 询问过程
            for (Object taskResult : taskResults) {
                if (200 == ((JSONObject) taskResult).getInteger("code")) {
                    JSONArray sceneResults = ((JSONObject) taskResult).getJSONArray("results");
                    for (Object sceneResult : sceneResults) {
                        // 获取文本结果
                        String suggestion = ((JSONObject) sceneResult).getString("suggestion");
                        //根据scene和suggetion做相关处理
                        return suggestion;
                    }
                } else {
                    System.out.println("询问过程失败:" + ((JSONObject) taskResult).getInteger("code"));
                    return null;
                }
            }
            return null;

        } catch (ServerException e) {
            e.printStackTrace();
        } catch (ClientException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }

        return null;
    }

    /**
     * 图片审核
     *
     * @param picUrls
     * @return
     * @throws Exception
     */
    public String imageReview(List<String> picUrls) throws Exception {
        IClientProfile profile = DefaultProfile
                .getProfile(regionId, accessKeyId, accessKeySecret);
        DefaultProfile
                .addEndpoint("cn-shanghai", "Green", "green.cn-shanghai.aliyuncs.com");
        IAcsClient client = new DefaultAcsClient(profile);

        ImageSyncScanRequest imageSyncScanRequest = new ImageSyncScanRequest();
        // 指定API返回格式。
        imageSyncScanRequest.setSysAcceptFormat(FormatType.JSON);
        // 指定请求方法。
        imageSyncScanRequest.setSysMethod(MethodType.POST);
        imageSyncScanRequest.setSysEncoding("utf-8");
        // 支持HTTP和HTTPS。
        imageSyncScanRequest.setSysProtocol(ProtocolType.HTTP);


        JSONObject httpBody = new JSONObject();
        /**
         * 设置要检测的风险场景。计费依据此处传递的场景计算。
         * 一次请求中可以同时检测多张图片，每张图片可以同时检测多个风险场景，计费按照场景计算。
         * 例如，检测2张图片，场景传递porn和terrorism，计费会按照2张图片鉴黄，2张图片暴恐检测计算。
         * porn：图片智能鉴黄
         * terrorism：图片暴恐涉政
         * ad：图文违规
         * qrcode：图片二维码
         * live：图片不良场景
         * logo：图片logo
         */
        httpBody.put("scenes", Arrays.asList("porn", "terrorism", "live"));

        // 循环获取图片的url
        List<JSONObject> tasks = new ArrayList<>();
        for (String picUrl : picUrls) {
            /**
             * 设置待检测图片。一张图片对应一个task。
             * 多张图片同时检测时，处理的时间由最后一个处理完的图片决定。
             * 通常情况下批量检测的平均响应时间比单张检测的要长。一次批量提交的图片数越多，响应时间被拉长的概率越高。
             * 这里以单张图片检测作为示例, 如果是批量图片检测，请自行构建多个task。
             */
            JSONObject task = new JSONObject();
            task.put("dataId", UUID.randomUUID().toString());

            // 设置图片链接。
            task.put("url", picUrl);
            task.put("time", new Date());
            tasks.add(task);
        }

        // 根据用户上传的图片数量进行赋值
        switch (tasks.size()) {
            case 1: {
                httpBody.put("tasks", Arrays.asList(tasks.get(0)));
                break;
            }
            case 2: {
                httpBody.put("tasks", Arrays.asList(tasks.get(0), tasks.get(1)));
                break;
            }
            case 3: {
                httpBody.put("tasks", Arrays.asList(tasks.get(0), tasks.get(1), tasks.get(2)));
                break;
            }
            case 4: {
                httpBody.put("tasks", Arrays.asList(tasks.get(0), tasks.get(1), tasks.get(2), tasks.get(3)));
                break;
            }
            case 5: {
                httpBody.put("tasks", Arrays.asList(tasks.get(0), tasks.get(1), tasks.get(2), tasks.get(3), tasks.get(4)));
                break;
            }
            case 6: {
                httpBody.put("tasks", Arrays.asList(tasks.get(0), tasks.get(1), tasks.get(2), tasks.get(3), tasks.get(4), tasks.get(5)));
                break;
            }
            case 7: {
                httpBody.put("tasks", Arrays.asList(tasks.get(0), tasks.get(1), tasks.get(2), tasks.get(3), tasks.get(4), tasks.get(5), tasks.get(6)));
                break;
            }
            case 8: {
                httpBody.put("tasks", Arrays.asList(tasks.get(0), tasks.get(1), tasks.get(2), tasks.get(3), tasks.get(4), tasks.get(5), tasks.get(6), tasks.get(7)));
                break;
            }
            case 9: {
                httpBody.put("tasks", Arrays.asList(tasks.get(0), tasks.get(1), tasks.get(2), tasks.get(3), tasks.get(4), tasks.get(5), tasks.get(6), tasks.get(7), tasks.get(8)));
                break;
            }
            default: {
                break;
            }
        }

        imageSyncScanRequest.setHttpContent(org.apache.commons.codec.binary.StringUtils.getBytesUtf8(httpBody.toJSONString()),
                "UTF-8", FormatType.JSON);

        /**
         * 请设置超时时间。服务端全链路处理超时时间为10秒，请做相应设置。
         * 如果您设置的ReadTimeout小于服务端处理的时间，程序中会获得一个ReadTimeout异常。
         */
        imageSyncScanRequest.setSysConnectTimeout(3000);
        imageSyncScanRequest.setSysReadTimeout(10000);
        HttpResponse httpResponse = null;
        try {
            httpResponse = client.doAction(imageSyncScanRequest);
        } catch (Exception e) {
            e.printStackTrace();
        }

        // 服务端接收到请求，完成处理后返回的结果。
        if (httpResponse != null && httpResponse.isSuccess()) {
            JSONObject scrResponse = JSON.parseObject(org.apache.commons.codec.binary.StringUtils.newStringUtf8(httpResponse.getHttpContent()));

            // 输出全状态
            //System.out.println(JSON.toJSONString(scrResponse, true));

            int requestCode = scrResponse.getIntValue("code");
            // 每一张图片的检测结果。
            JSONArray taskResults = scrResponse.getJSONArray("data");
            if (200 == requestCode) {
                for (Object taskResult : taskResults) {
                    // 单张图片的处理结果。
                    int taskCode = ((JSONObject) taskResult).getIntValue("code");
                    // 图片对应检测场景的处理结果。如果是多个场景，则会有每个场景的结果。
                    JSONArray sceneResults = ((JSONObject) taskResult).getJSONArray("results");
                    if (200 == taskCode) {
                        for (Object sceneResult : sceneResults) {
                            String scene = ((JSONObject) sceneResult).getString("scene");
                            String suggestion = ((JSONObject) sceneResult).getString("suggestion");
                            // 根据scene和suggestion做相关处理。
                            // 根据不同的suggestion结果做业务上的不同处理。例如，将违规数据删除等。
//                            System.out.println("scene = [" + scene + "]");
                            return suggestion;
                        }
                    } else {
                        // 单张图片处理失败, 原因视具体的情况详细分析。
                        System.out.println("task process fail. task response:" + JSON.toJSONString(taskResult));
                        return null;
                    }
                }
            } else {
                /**
                 * 表明请求整体处理失败，原因视具体的情况详细分析。
                 */
                System.out.println("the whole image scan request failed. response:" + JSON.toJSONString(scrResponse));
                return null;
            }
        }
        return null;
    }

    /**
     * 提取图片文字
     *
     * @param multipartFile 图片
     * @return
     */
    public boolean extractImageText(MultipartFile[] multipartFile) {

        try {
            // 语言库位置（修改为跟自己语言库文件夹的路径）
            String lagnguagePath = "E:\\TessData";

            ITesseract instance = new Tesseract();
            //设置训练库的位置
            instance.setDatapath(lagnguagePath);

            /**
             * 语言库
             * chi_sim ：简体中文
             * eng : 英语
             */
            instance.setLanguage("chi_sim");
            // 循环获取全部图片
            for (MultipartFile mFile : multipartFile) {
                // 调用 MultipartFile 转 File 方法
                File file = multipartFileToFile(mFile);

                // 提取图片文字
                String result = instance.doOCR(file);

                // 判断图片文字是否违规
                Boolean imageFlag = isImageText(result);

                if (!imageFlag) {
                    return false;
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        return true;
    }

    /**
     * 自定义敏感词判断
     *
     * @param text 要验证的字
     * @return 过滤后的结果
     */
    public Boolean isImageText(String text) {
        // 搜索器组,构建敏感词管理器,可同时管理多个搜索器，
        KWSeekerManage kwSeekerManage = SimpleKWSeekerProcessor.newInstance();

        // 调用配置文件词库
        List<SensitiveWordResult> words = kwSeekerManage.getKWSeeker("comment-sensitive-word")
                .findWords(text);
        // 判断是否违规
        if (!StrUtil.equals(words + "", "[]")) {
            return false;
        }
        return true;
    }

    /**
     * MultipartFile 转 File
     *
     * @param file
     * @return
     * @throws Exception
     */
    public static File multipartFileToFile(MultipartFile file) throws Exception {

        File toFile = null;
        if (file.equals("") || file.getSize() <= 0) {
            file = null;
        } else {
            InputStream ins = null;
            ins = file.getInputStream();
            toFile = new File(file.getOriginalFilename());
            inputStreamToFile(ins, toFile);
            ins.close();
        }
        return toFile;
    }

    //获取流文件
    private static void inputStreamToFile(InputStream ins, File file) {
        try {
            OutputStream os = new FileOutputStream(file);
            int bytesRead = 0;
            byte[] buffer = new byte[8192];
            while ((bytesRead = ins.read(buffer, 0, 8192)) != -1) {
                os.write(buffer, 0, bytesRead);
            }
            os.close();
            ins.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
